home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Diamond Collection / The Diamond Collection (Software Vault)(Digital Impact).ISO / cdr13 / gc0165.zip / RTFREADR.C < prev    next >
C/C++ Source or Header  |  1993-11-19  |  7KB  |  296 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <ctype.h>
  4. #include "rtftype.h"
  5. #include "rtfdecl.h"
  6.  
  7. int cGroup;
  8. bool fSkipDestIfUnk;
  9. long cbBin;
  10. long lParam;
  11.  
  12. RDS rds;
  13. RIS ris;
  14.  
  15. CHP chp;
  16. PAP pap;
  17. SEP sep;
  18. DOP dop;
  19.  
  20. SAVE *psave;
  21. FILE *fpIn;
  22.  
  23. //
  24. // %%Function: main
  25. //
  26. // Main loop.  Initialize and parse RTF.
  27. //
  28. main(int argc, char *argv[])
  29. {
  30.     FILE *fp;
  31.     int ec;
  32.  
  33.     fp = fpIn = fopen("test.rtf", "r");
  34.     if (!fp)
  35.     {
  36.         printf ("Can't open test file!\n");
  37.         return 1;
  38.     }
  39.     if ((ec = ecRtfParse(fp)) != ecOK)
  40.         printf("error %d parsing rtf\n", ec);
  41.     else
  42.         printf("Parsed RTF file OK\n");
  43.     fclose(fp);
  44.     return 0;
  45. }
  46.  
  47. //
  48. // %%Function: ecRtfParse
  49. //
  50. // Step 1:
  51. // Isolate RTF keywords and send them to ecParseRtfKeyword;
  52. // Push and pop state at the start and end of RTF groups;
  53. // Send text to ecParseChar for further processing.
  54. //
  55.  
  56. int
  57. ecRtfParse(FILE *fp)
  58. {
  59.     int ch;
  60.     int ec;
  61.     int cNibble = 2;
  62.     int b = 0;
  63.     while ((ch = getc(fp)) != EOF)
  64.     {
  65.         if (cGroup < 0)
  66.             return ecStackUnderflow;
  67.         if (ris == risBin)                      // if we're parsing binary data, handle it directly
  68.         {
  69.             if ((ec = ecParseChar(ch)) != ecOK)
  70.                 return ec;
  71.         }
  72.         else
  73.         {
  74.             switch (ch)
  75.             {
  76.             case '{':
  77.                 if ((ec = ecPushRtfState()) != ecOK)
  78.                     return ec;
  79.                 break;
  80.             case '}':
  81.                 if ((ec = ecPopRtfState()) != ecOK)
  82.                     return ec;
  83.                 break;
  84.             case '\\':
  85.                 if ((ec = ecParseRtfKeyword(fp)) != ecOK)
  86.                     return ec;
  87.                 break;
  88.             case 0x0d:
  89.             case 0x0a:          // cr and lf are noise characters...
  90.                 break;
  91.             default:
  92.                 if (ris == risNorm)
  93.                 {
  94.                     if ((ec = ecParseChar(ch)) != ecOK)
  95.                         return ec;
  96.                 }
  97.                 else
  98.                 {               // parsing hex data
  99.                     if (ris != risHex)
  100.                         return ecAssertion;
  101.                     b = b << 4;
  102.                     if (isdigit(ch))
  103.                         b += (char) ch - '0';
  104.                     else
  105.                     {
  106.                         if (islower(ch))
  107.                         {
  108.                             if (ch < 'a' || ch > 'f')
  109.                                 return ecInvalidHex;
  110.                             b += (char) ch - 'a';
  111.                         }
  112.                         else
  113.                         {
  114.                             if (ch < 'A' || ch > 'F')
  115.                                 return ecInvalidHex;
  116.                             b += (char) ch - 'A';
  117.                         }
  118.                     }
  119.                     cNibble--;
  120.                     if (!cNibble)
  121.                     {
  122.                         if ((ec = ecParseChar(ch)) != ecOK)
  123.                             return ec;
  124.                         cNibble = 2;
  125.                         b = 0;
  126.             ris = risNorm;
  127.                     }
  128.                 }                   // end else (ris != risNorm)
  129.                 break;
  130.             }       // switch
  131.         }           // else (ris != risBin)
  132.     }               // while
  133.     if (cGroup < 0)
  134.         return ecStackUnderflow;
  135.     if (cGroup > 0)
  136.         return ecUnmatchedBrace;
  137.     return ecOK;
  138. }
  139.  
  140. //
  141. // %%Function: ecPushRtfState
  142. //
  143. // Save relevant info on a linked list of SAVE structures.
  144. //
  145.  
  146. int
  147. ecPushRtfState(void)
  148. {
  149.     SAVE *psaveNew = malloc(sizeof(SAVE));
  150.     if (!psaveNew)
  151.         return ecStackOverflow;
  152.  
  153.     psaveNew -> pNext = psave;
  154.     psaveNew -> chp = chp;
  155.     psaveNew -> pap = pap;
  156.     psaveNew -> sep = sep;
  157.     psaveNew -> dop = dop;
  158.     psaveNew -> rds = rds;
  159.     psaveNew -> ris = ris;
  160.     ris = risNorm;
  161.     psave = psaveNew;
  162.     cGroup++;
  163.     return ecOK;
  164. }
  165.  
  166. //
  167. // %%Function: ecPopRtfState
  168. //
  169. // If we're ending a destination (i.e., the destination is changing),
  170. // call ecEndGroupAction.
  171. // Always restore relevant info from the top of the SAVE list.
  172. //
  173.  
  174. int
  175. ecPopRtfState(void)
  176. {
  177.     SAVE *psaveOld;
  178.     int ec;
  179.  
  180.     if (!psave)
  181.         return ecStackUnderflow;
  182.  
  183.     if (rds != psave->rds)
  184.     {
  185.         if ((ec = ecEndGroupAction(rds)) != ecOK)
  186.             return ec;
  187.     }
  188.     chp = psave->chp;
  189.     pap = psave->pap;
  190.     sep = psave->sep;
  191.     dop = psave->dop;
  192.     rds = psave->rds;
  193.     ris = psave->ris;
  194.  
  195.     psaveOld = psave;
  196.     psave = psave->pNext;
  197.     cGroup--;
  198.     free(psaveOld);
  199.     return ecOK;
  200. }
  201.  
  202. //
  203. // %%Function: ecParseRtfKeyword
  204. //
  205. // Step 2:
  206. // get a control word (and it's associated value) and
  207. // call ecTranslateKeyword to dispatch the control.
  208. //
  209.  
  210. int
  211. ecParseRtfKeyword(FILE *fp)
  212. {
  213.     int ch;
  214.     char fParam = fFalse;
  215.     char fNeg = fFalse;
  216.     int param = 0;
  217.     char *pch;
  218.     char szKeyword[30];
  219.     char szParameter[20];
  220.  
  221.     szKeyword[0] = '\0';
  222.     szParameter[0] = '\0';
  223.     if ((ch = getc(fp)) == EOF)
  224.         return ecEndOfFile;
  225.     if (!isalpha(ch))           // a control symbol; no delimiter.
  226.     {
  227.         szKeyword[0] = (char) ch;
  228.         szKeyword[1] = '\0';
  229.         return ecTranslateKeyword(szKeyword, 0, fParam);
  230.     }
  231.     for (pch = szKeyword; isalpha(ch); ch = getc(fp))
  232.         *pch++ = (char) ch;
  233.     *pch = '\0';
  234.     if (ch == '-')
  235.     {
  236.         fNeg  = fTrue;
  237.         if ((ch = getc(fp)) == EOF)
  238.             return ecEndOfFile;
  239.     }
  240.     if (isdigit(ch))
  241.     {
  242.         fParam = fTrue;         // a digit after the control means we have a parameter
  243.         for (pch = szParameter; isdigit(ch); ch = getc(fp))
  244.             *pch++ = (char) ch;
  245.         *pch = '\0';
  246.         param = atoi(szParameter);
  247.         if (fNeg)
  248.             param = -param;
  249.         lParam = atol(szParameter);
  250.         if (fNeg)
  251.             param = -param;
  252.     }
  253.     if (ch != ' ')
  254.         ungetc(ch, fp);
  255.     return ecTranslateKeyword(szKeyword, param, fParam);
  256. }
  257.  
  258. //
  259. // %%Function: ecParseChar
  260. //
  261. // Route the character to the appropriate destination stream.
  262. //
  263.  
  264. int
  265. ecParseChar(int ch)
  266. {
  267.     if (ris == risBin && --cbBin <= 0)
  268.         ris = risNorm;
  269.     switch (rds)
  270.     {
  271.     case rdsSkip:
  272.         // Toss this character.
  273.         return ecOK;
  274.     case rdsNorm:
  275.         // Output a character.  Properties are valid at this point.
  276.         return ecPrintChar(ch);
  277.     default:
  278.     // handle other destinations....
  279.         return ecOK;
  280.     }
  281. }
  282.  
  283. //
  284. // %%Function: ecPrintChar
  285. //
  286. // Send a character to the output file.
  287. //
  288.  
  289. int
  290. ecPrintChar(int ch)
  291. {
  292.     // unfortunately, we don't do a whole lot here as far as layout goes...
  293.     putchar(ch);
  294.     return ecOK;
  295. }
  296.